<!doctype html>
<html lang="en">

	<head>
		<meta charset="utf-8">

		<title>Containers from Scratch workshop</title>

		<meta name="description" content="Build a container tool from syscall primitives">
		<meta name="author" content="Avishai Ish-Shalom">

		<meta name="apple-mobile-web-app-capable" content="yes">
		<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">

		<script src="https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/lib/js/head.min.js"></script>

		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/css/reveal.css">
		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/css/theme/black.css" id="theme">

		<!-- Code syntax highlighting -->
		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/lib/css/zenburn.css">

		<!-- Printing and PDF exports -->
		<script>
			var link = document.createElement( 'link' );
			link.rel = 'stylesheet';
			link.type = 'text/css';
			link.href = window.location.search.match( /print-pdf/gi ) ? 'https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/css/print/pdf.css' : 'https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/css/print/paper.css';
			document.getElementsByTagName( 'head' )[0].appendChild( link );
		</script>

		<style>
			.reveal pre {
				box-shadow: none;
			}
		</style>

		<!--[if lt IE 9]>
		<script src="reveal.js/reveal.js/lib/js/html5shiv.js"></script>
		<![endif]-->
	</head>

	<body>

		<div class="reveal">

			<!-- Any section element inside of this container is displayed as a slide -->
			<div class="slides">
				<section>
					<h1>Containers from Scratch</h1>
					<p>Nati Cohen (@nocoot)<br>Avishai Ish-Shalom (@nukemberg)</p>
				</section>

				<section>
					<section>
						<h2>Workshop goal</h2>
						<p>Understand how containers work in terms of kernel constructs:
						<ul>
							<li>Namespaces</li>
							<li>CGroups</li>
							<li>CoW filesystem</li>
						</ul>
						</p>
					</section>
					<section>
						<p>"Container" is not a kernel primitive</p>
						<img src="images/there-is-no-container.jpg" alt="" />
						<p>It is a combination of various kernel mechanisms</p>
					</section>
					<section>
						<h2>Docker highlevel architecture</h2>
						<div>
						<img src="images/docker-architecture.svg" style="height: 350px;">
						</div>
						<p>We're building part of libcontainer + daemon + cli</p>
					</section>
				</section>
				<section>
					<section>
						<h1>Let's build!</h1>
						<div>
							<p>Workshop material is in <code>/workshop</code></p>
							<p>
								<pre>
									<code data-trim data-noescape>cd /workshop/rubber-docker/levels/00_fork_exec</code>
								</pre>
								try to run <code>rd.py</code>
								<pre>
									<code data-trim data-noescape>python rd.py run /bin/echo "Hello Docker"</code>
								</pre>
							</p>
						</div>
					</section>
					<section>
						<h2><span style="text-transform: none;"><i>fork</i> &amp; <i>exec</i></span> a process</h2>
					</section>
					<section>
						<h2 style="text-transform: none;"><i>chroot</i></h2>
						<h4>Maybe unpack an image too?</h4>
					</section>
				</section>
				<section>
					<section>
						<h2>Namespaces</h2>
						<p><p>The namespaces API:</p>
							<ul>
								<li><i>clone</i></li>
								<li><i>unshare</i></li>
								<li><i>setns</i></li>
							</ul>
						</p>
					</section>
					<section>
						<h2>The mount namespace</h2>
					</section>
					<section>
						<h2 style="text-transform: none;"><i>pivot_root</i></h2>
						<p>
							<ul>
								<li>Don't forget to mount private (recursively) the original root filesystem (why?)</li>
								<li>Finally, remove the old root directory</li>
							</ul>
						</p>
						<h3 class="fragment">Doesn't work? new_root must be a mount!</h3>
					</section>
					<section>
						<h2>CoW FTW!</h2>
						<p>
							<p>Mount an <i>overlay</i> filesystem as the rootfs</p>
							<ul>
								<li>Use the extracted image rootfs dir as <i>lowerdir</i></li>
								<li>Create an <i>upperdir</i> and <i>workdir</i> per container</li>
							</ul>
						</p>
						<h3>Now we can <i>pivot_root</i> into the CoW mount</h3>
					</section>
					<section>
						<h2>UTS namespace and hostname</h2>
					</section>
					<section>
						<h2>PID namespace</h2>
						<p><i>unshare</i> CLONE_NEWPID before forking a new process</p>
						<p>Can also be done via <i>clone</i></p>
					</section>
					<section>
						<h2>Network namespace</h2>
					</section>
				</section>
				<section>
					<section>
						<h2>CGroups</h2>
					</section>
					<section>
						<h2>The CPU controller</h2>
						<p><p>Open a new cpu cgroup for each container. Set <i>cpu.shares</i></p>
							<h4>Questions</h4>
							<ul>
								<li>Are processes always throttled?</li>
								<li>How much is a <i>share</i>?</li>
								<li>How does this limit relate to scheduling priorities and classes?</li>
							</ul>
						</p>
					</section>
					<section>
						<h2>The Memory controller</h2>
						<p><p>Open a new memory cgroup for each container. Configure the following:</p>
							<ul>
								<li>memory.limit_in_bytes</li>
								<li>memory.memsw.limit_in_bytes</li>
								<li>memory.kmem.limit_in_bytes</li>
								<li>memory.oom_control</li>
							</ul>
							<p>Run stress and observe how the container behaves with(out) oom killer</p>
						</p>
					</section>
				</section>
				<section>
					<section>
						<h1>Bonus round!</h1>
					</section>
					<section>
						<h2>exec</h2>
						<p><i>docker exec</i> like functionality</p>
						<p>Write the pid to a file, then use it's namespace references with <i>setns</i></p>
					</section>
					<section>
						<h2>run -d (background)</h2>
					</section>
					<section>
						<h2>Capabilities</h2>
					</section>
					<section>
						<h2>Volumes</h2>
						<p>mount bind</p>
					</section>
					<section>
						<h2>Devices whitelist controller</h2>
					</section>
					<section>
						<h2>Internal NIC &amp; port mappings</h2>
					</section>
					<section>
						<h2>setuid</h2>
					</section>
				</section>
				<section>
					<img src="images/thats-all-folks.jpg">
					<p>Workshop materials: <a href="https://github.com/Fewbytes/rubber-docker">github.com/Fewbytes/rubber-docker</a><br>
					Preparation talk slides: <a href="https://docs.google.com/presentation/d/10vFQfEUvpf7qYyksNqiy-bAxcy-bvF0OnUElCOtTTRc/edit?usp=sharing">Google docs</a></p>
				</section>
			</div>

		</div>

		<script src="https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/js/reveal.min.js"></script>

		<script>

			// Full list of configuration options available at:
			// https://github.com/hakimel/reveal.js#configuration
			Reveal.initialize({
				controls: true,
				progress: true,
				history: true,
				center: true,

				transition: 'slide', // none/fade/slide/convex/concave/zoom

				// Optional reveal.js plugins
				dependencies: [
					{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/lib/js/classList.js', condition: function() { return !document.body.classList; } },
					{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
					{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
					{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
					{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/plugin/zoom-js/zoom.js', async: true },
					{ src: 'https://cdn.jsdelivr.net/npm/reveal.js@3.6.0/plugin/notes/notes.js', async: true }
				]
			});

		</script>

	</body>
</html>
